<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Marginalia Unit Tests</title>
<link rel="stylesheet" type="text/css" href="../css/jsUnitStyle.css">
<script language="JavaScript" type="text/javascript" src="../app/jsUnitCore.js"></script>
<script type="text/javascript" src="../../marginalia/log.js"></script>
<script type="text/javascript" src="../../marginalia/html-model.js"></script>
<script type="text/javascript" src="../../marginalia/domutil.js"></script>
<script type="text/javascript" src="../../marginalia/ranges.js"></script>
<script type="text/javascript" src="../../marginalia/SequenceRange.js"></script>
<script type="text/javascript" src="../../marginalia/XPathRange.js"></script>
<script language="javaScript" type="text/javascript">

function myload()
{
	window.log = new ErrorLogger( true, true );
	window.log.setTrace( 'WordRange', true );			// Check if quote matches current state of document
	window.log.setTrace( 'WordPointWalker', true );
}

function makeXPathRange( sequenceStr )
{
	var root = document.getElementById( 'xpath-data' );

	var sequenceRange = SequenceRange.fromString( sequenceStr );
	assertTrue( 'test sequence range parse', sequenceRange.toString() == sequenceStr );
	
	var wordRange = WordRange.fromSequenceRange( sequenceRange, root );
	sequenceRange = wordRange.toSequenceRange( root );
	assertTrue( 'sequence range = ' + sequenceRange.toString() + ', expect ' + sequenceStr, sequenceRange.toString() == sequenceStr );
	
	return {
		root:  root,
		wordRange: wordRange,
		xpathRange: wordRange.toXPathRange( root )
	};
}

function testXPathRangeWithId( )
{
	var ranges = makeXPathRange( '1.1/1.3.0;1.1/1.3.2' ); //( '/1/1/3.0;/1/1/3.2' );
	xpath = ranges.xpathRange.toString( );
	var expect = ".//*[@id='xbq1']/line(1)/word(3)/char(0);.//*[@id='xbq1']/line(1)/word(3)/char(2)";
	assertTrue( 'xpath ' + xpath + ' = expect ' + expect, xpath == expect );
	
	var wordRange = WordRange.fromXPathRange( ranges.xpathRange, ranges.root );
	assertTrue( 'Test xpath range with ID resolution', wordRange.equals( ranges.wordRange ) );
}

function testXPathRangeFollowingId( )
{
	var ranges = makeXPathRange( '1.2/1.2.0;1.2/1.2.4' ); //( '/1/2/2.0;/1/2/2.4' );
	xpath = ranges.xpathRange.toString( );
	var expect = ".//*[@id='xbq1']/following-sibling::html:blockquote[1]/line(1)/word(2)/char(0);.//*[@id='xbq1']/following-sibling::html:blockquote[1]/line(1)/word(2)/char(4)";
	assertTrue( 'xpath ' + xpath + ' = expect ' + expect, xpath == expect );
	
	var wordRange = WordRange.fromXPathRange( ranges.xpathRange, ranges.root );
	assertTrue( 'Test xpath range with ID resulotion', wordRange.equals( ranges.wordRange ) );
}

function rangeConversionTest( in_t, in_s, in_q )
{
	var conv = { t: in_t, s: in_s, q: in_q };
	var rel = document.getElementById( 'word-data' );

	conv.textRange = TextRange.fromString( conv.t );
	inform( 'Conversion test for', conv.s );
	conv.sequenceRange = SequenceRange.fromString( conv.s );
	assertEquals( 'String from/to conversion', conv.sequenceRange.toString( ), conv.s ) ;
	
	// TestWord Range -> TextRange conversion
	var wordRange = WordRange.fromTextRange( conv.textRange, rel, null );
//	inform( 'TextRange: ' + conv.textRange.startContainer + '#' + conv.textRange.startContainer.id + ' to '
//		+ conv.textRange.endContainer + '#' + conv.textRange.endContainer.id );
	inform( 'wordRange: ' + wordRange.start.rel + '#' + wordRange.start.rel.id + ' to '
		+ wordRange.end.rel + '#' + wordRange.end.rel.id );
	var sequenceRange = wordRange.toSequenceRange( rel ); 
	var s = sequenceRange.toString( );
	var s2 = '';
	for ( var i = 0;  i < conv.sequenceRange.start.path.length;  ++i )
		s2 += ' .' + conv.sequenceRange.start.path[ i ];
	inform( 'conv.sequenceRange start path: ' + s2 );
	assertTrue( '1 Convert ' + conv.t + ' to ' + conv.s,
		conv.sequenceRange.equals( sequenceRange ) );
	
	// Test TextRange -> WordRange conversion
	trace( null, '-> wordrange' );
	wordRange = WordRange.fromSequenceRange( conv.sequenceRange, rel, null );
	trace( null, '-> wordrange(2)' );
	inform( 'wordRange start rel ' + wordRange.start.rel + ', lines ' + wordRange.start.lines );
	textRange = TextRange.fromWordRange( wordRange );
	trace( null, '-> wordrange(3)' );
	var wordRange2 = WordRange.fromTextRange( conv.textRange, rel, null );
	assertTrue( 'Convert ' + conv.s + ' to ' + conv.t, wordRange.equals( wordRange2 ) );
		
	// Test range partition
	trace (null, 'partition' );
	var parts = wordRange.partition( );
	var actual = parts.quote.replace( /\s+|\u00a0\s*/g, ' ' );
	var quote = conv.q.replace( /\s+|\u00a0\s*/g, ' ' );
	trace( null, 'Actual: <' + actual + '>, quote: <' + quote + '>' );
	assertTrue( 'Range ' + conv.s + ' actual quote "' + actual + '" == expected "' + quote + '"', actual == quote );
}

function testRange_Image( )
{
	rangeConversionTest( 'sol1.2.0;sli1.2.4', '7.1/1.1.0;7.1/1.1.4', 'fred' );
}

function testRange_ElementBoundary( )
{
	// crossing breaking element boundary
	rangeConversionTest( 'li1.1.28;li2.1.4', '6.1/1.7.0;6.2/1.1.2', "hand: Lo" );
}

function testRange_wordInTag( )
{
	// 5 chars in, then start tag, with <= 5 chars to go
	rangeConversionTest( 'p5.1.5;em4.1.4', '5/1.2.0;5/1.2.7', 'brillig' );
}

function testRange_firstChar( )
{
	rangeConversionTest( 'p1.1.0;p1.1.1', '1/1.1.0;1/1.1.1', 'o' );
}
		
function testRange_loneWord( )
{
	// word alone in block
	rangeConversionTest( 'p1.1.0;p1.1.3', '1/1.1.0;1/1.1.3', 'one' );
}

function testRange_followingSpace( )
{
	// following space
	rangeConversionTest( 'p2.1.0;p2.1.5', '2/1.1.0;2/1.1.3', 'two' );
}

function testRange_spaces( )
{
	rangeConversionTest( 'p2.1.5;p2.1.10', '2/1.2.0;2/1.2.5', 'three' );
}
	
function testRange_endSpaces( )
{
	// spaces at either end
	rangeConversionTest( 'p3.1.0;p3.1.6', '3/1.1.0;3/1.1.4', 'four' );
}

function testRange_nonbreaking( )
{
	// non-breaking element
	rangeConversionTest( 'em1.1.0;em1.1.4', '3/1.2.0;3/1.2.4', 'five' );
}

function testRange_crossEmStart( )
{
	// cross em start boundary
	rangeConversionTest( 'p3.1.6;em1.1.4', '3/1.2.0;3/1.2.4', 'five' );
}

function testRange_crossEmEnd( )
{
	// cross em end boundary
	rangeConversionTest( 'em1.1.0;p3.3.0', '3/1.2.0;3/1.2.4', 'five' );
}

function testRange_crossEmEndStart( )
{
	// cross em end/start
	rangeConversionTest( 'em2.1.0;em3.1.5', '4/1.1.0;4/1.1.10', 'sevenseven' );
}

function testRange_spanParagraphs( )
{
	rangeConversionTest( 'p1.1.0;p2.1.4', '1/1.1.0;2/1.1.3', 'one two' );
}

function testRange_fromNested( )
{
	// from preceding nested element
	rangeConversionTest( 's1.1.0;s1.1.3', '6.4/1.6.0;6.4/1.6.3', 'And' );
}

function testRange_crossBR( )
{
	// cross BR tag
	rangeConversionTest( 's1.1.0;s2.1.3', '6.4/1.6.0;6.4/2.1.3', 'And while in uffish thought he stood The' );
}

function testRange_inRoot( )
{
	rangeConversionTest( 'word-data.1.10;word-data.1.21', '/1.2.0;/1.4.4', 'in the root' );
}

function testRange_invalidBlock( )
{
	rangeConversionTest( 'p7.1.0;p7.1.5', '8/2.3.0;8/2.3.5', 'Three' );
}


function testSequencePointOrder( )
{
	var r1 = new SequencePoint( '2.3/1.4.5' );
	var r2 = new SequencePoint( '2.3/1.4.6' );
	var r3 = new SequencePoint( '2.3/1.3.5' );
	var r4 = new SequencePoint( '2.4/1.3.2' );
	var r5 = new SequencePoint( '3.2/1.2.1' );
	var r6 = new SequencePoint( '2/1.4.6' );
	// No longer supported:
	// var r7 = new SequencePoint( '2/3' );
	// var r8 = new SequencePoint( '2/4' );
	
	assertTrue( r1.compare( r1 ) == 0 );
	assertTrue( r1.compare( r2 ) < 0 );
	assertTrue( r2.compare( r1 ) > 0 );
	assertTrue( r1.compare( r3 ) > 0 );
	assertTrue( r1.compare( r4 ) < 0 );
	assertTrue( r1.compare( r5 ) < 0 );
	// assertTrue( r7.compare( r8 ) < 0 );
}

function testSequenceRangeOrder( )
{
	var r1 = SequenceRange.fromString( '2/1.3.0;2/1.3.4' );
	var r2 = SequenceRange.fromString( '2/1.3.1;2/1.3.2' );
	var r3 = SequenceRange.fromString( '2/1.3.0;2/1.3.5' );
	var r4 = SequenceRange.fromString( '2/1.2.5;2/1.2.6' );
	var r5 = SequenceRange.fromString( '2/1.2.5;2/1.4.5' );
	var r6 = SequenceRange.fromString( '3/1.2.0;3/1.2.1' );
	
	assertTrue( r1.compare( r1 ) == 0 );
	assertTrue( r1.compare( r2 ) < 0 );
	assertTrue( r1.compare( r3 ) < 0 );
	assertTrue( r1.compare( r4 ) > 0 );
	assertTrue( r1.compare( r5 ) > 0 );
	assertTrue( r1.compare( r6 ) < 0 );
}

function testClosestPrecedingBreakingElement( )
{
	// Just to be sure the conversion for s1.1.0;s1.1.3 works correctly
	var s1 = document.getElementById( 's1' );
	var node = domutil.closestPrecedingBreakingElement( s1 );
	assertTrue( 'Closest preceding breaking is li2', node.id == 'li4' );
	node = domutil.closestPrecedingBreakingElement( s1.firstChild );
	assertTrue( 'Closest preceding breaking (text) is li2', node.id == 'li4' );
}

TextRange.fromString = function( str )
{
	var points = str.split( ';' );
	
	// Get the start point
	var parts = points[ 0 ].split( '.' );
	var element = document.getElementById( parts[ 0 ] );
	var childIndex = Number( parts[ 1 ] ) - 1;
	var startContainer = element.childNodes[ childIndex ];
	var startOffset = Number( parts[ 2 ] )
	
	// Get the end point
	parts = points[ 1 ].split( '.' );
	element = document.getElementById( parts[ 0 ] );
	childIndex = Number( parts[ 1 ] ) - 1;
	var endContainer = element.childNodes[ childIndex ];
	var endOffset = Number( parts[ 2 ] );
	
	var textRange = new TextRange( startContainer, startOffset, endContainer, endOffset );
	return textRange.shrinkwrap( );
}
</script>
</head>

<body onload='myload()'>
<h1>Marginalia Range Format Conversion Tests</h1>

<button onclick="testRangeConversion()">Run Test</button>

<div id="word-data">
Directly in the root.
<p id="p1">one</p>
<p id="p2"> two three  </p>
<p id="p3"> four <em id="em1">five</em> six </p>
<p id="p4"> <em id="em2">seven</em><em id="em3">seven</em> </p>
<p id="p5">Twas bri<em id="em4" class="annotation annot3 last">llig,</em> and the slithy toves</p>
<ul id="ul1">
<li id="li1">He took his vorpal sword in hand:</li>
<li id="li2">  Long time the manxome foe he sought --</li>
<li id="li3">So rested he by the Tumtum tree,</li>
<li id="li4">  And stood awhile in thought.</li>
</ul>
<span id="s1">And while in uffish thought he stood</span><br id="br1"
/><span id="s2">The Jabberwock, with eyes of flame, came wiffling through the tulgey wood.</span>

<ol id="sol1">
<li id="sli1"><img src="shy.gif" alt="shy" />fred</li>
</ol>

<p id='p6'>
One <br>break <span id='s3'>Two<blockquote id='bq1'><p id='p7'>Three</p></blockquote></span>
</p>
</div>

<div id="xpath-data">
<div id="xdiv1">"Beware <blockquote id="xbq1">the <span id="xspan1">Jabberwock, my son!</span>
  The </blockquote>jaws that bite,<blockquote> the claws that catch!</blockquote>
Beware the Jubjub bird, and shun
  The frumious Bandersnatch!"</div>
</div>

</body>
</html>
